/* ****************************************************************************
 *
 * Copyright (c) Microsoft Corporation. 
 *
 * This source code is subject to terms and conditions of the Microsoft Public License. A 
 * copy of the license can be found in the License.html file at the root of this distribution. If 
 * you cannot locate the  Microsoft Public License, please send an email to 
 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 *
 * You must not remove this notice, or any other, from this software.
 *
 * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
 * PARTICULAR PURPOSE.
 * ***************************************************************************/



#if !defined(AFX_LINE2DGL_H__4DACBB78_9EFC_11D4_8A95_D4B14EEC3D7F__INCLUDED_)
#define AFX_LINE2DGL_H__4DACBB78_9EFC_11D4_8A95_D4B14EEC3D7F__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <pgl/core/PGLLine.h>
#include <pgl/core/PGLData.h>

/*! \struct SPGLArrow

  A description structure
	\ingroup PGLStruct
*/
struct SPGLArrow
{
	//! Visibility bit
	bool m_bVisible;
	//! Arrow thickness (in pixels)
	double m_dThick;
	//! Arrow length (in pixels)
	double m_dLength;
};

/*! \brief A 2D curve class.

\ingroup PGLLineGroup
The curve is represented by a points, wich are given by the user.
All the memory handling is taken care of by PGL.

\b Example: How to plot a function f(x) ?
<ol>
<li>Generate pair of points (x,f(x))
\code
using namespace std;

int nPoints; // number of poitns
vector<double> vX(nPoints;
vector<double> vY(nPoints);

// Generating data
for (int i=0;i<nPoints;i++)
{
    vX[i]= // put your function here
    vY[i]= // put your function here
}
\endcode
<li> Create line CPGLLine2D object and assign data to it.
\code
	CPGLLine2D* pLine2D=new CPGLLine2D();
	pLine2D->SetDatas(vX,vY);
\endcode
<li>Change characteristics of the line (for example change linewidth):
\code 
	pLine2D->SetLineWidth(2.0f);
\endcode
<li>Add this line a CPGLGraph object.
\code
  CPGLRegion* pRegion;
  ...
  pRegion->AddObject(pLine2D);
\endcode
  </ol>

*/
class PGLCORE_EXT_CLASS CPGLLine2D : public CPGLLine  
{
PGL_DECLARE_DYNCREATE(CPGLLine2D);
public:
    //! \name Constructor
    //@{
    //! default constructor
    CPGLLine2D(const CPGLColor& _FrontColor = CPGLColor(0,0,0,1), const CPGLColor& _FillColor = CPGLColor(0.3f,0.3f,0.3f,1));
    //! copy constructor
    CPGLLine2D(const CPGLLine2D& l):m_pX(CPGLDataPtr()), m_pY(CPGLDataPtr()) {*this = l;};
    //! assignement constructor
    CPGLLine2D& operator=(const CPGLLine2D& l);
    //! desctructor
	virtual ~CPGLLine2D();
	//@}

	//! Extent computation
    virtual void GetUnionExtent(gfxinterface::CGfxInterface& gfx, CPGLRectD& rExtent);
    //! virtual function to override in derived classes
    virtual void UpdateExtent(gfxinterface::CGfxInterface& gfx);

	//! \name GUI
	//@{
    //! adds context menu items...
    virtual void AddContextMenuItems(CMenu* pMenu);
    //! adds the Line2D property page to the property dialog
    virtual void AddPropertyPage(CPropertySheet* pPropSheet);
	//@}

	//! \name Arrows (not working yet)
	//@{
	//! TRUE if there is an arrow at the beginning of the line
	bool IsStartArrow() const				{	return m_StartArrow.m_bVisible;};
	//! TRUE if there is an arrow at the end of the line
	bool IsEndArrow() const					{	return m_EndArrow.m_bVisible;};
	//! shows start arrow (default is yes)
	void ShowStartArrow(bool show=TRUE)		{	m_StartArrow.m_bVisible=show;};
	//! shows end arrow (default is yes)
	void ShowEndArrow(bool show=TRUE)		{	m_EndArrow.m_bVisible=show;};
	/*! \brief Get start arrow length

	Returns the start arrow length in pixels.
	\sa GetEndArrowLength
	\sa SetStartArrowLength
	\sa SetEndArrowLength
	\sa IsStartArrow
	\sa IsEndArrow
	*/
	double GetStartArrowLength() const	{	return m_StartArrow.m_dLength;};
	/*! \brief Get end arrow length

	Returns the end arrow length in pixels.
	\sa GetStartArrowLength
	\sa SetStartArrowLength
	\sa SetEndArrowLength
	\sa IsStartArrow
	\sa IsEndArrow
	*/
	double GetEndArrowLength() const		{	return m_EndArrow.m_dLength;};
	//! Return the start arrow thick (in pixels)
	double GetStartArrowThick() const		{	return m_StartArrow.m_dThick;};
	//! Return the end arrow thick (in pixels)
	double GetEndArrowThick() const			{	return m_StartArrow.m_dThick;};
	//! Set the start arrow length (in pixels)
	void SetStartArrowLength(double length)	{	m_StartArrow.m_dLength=__max(0,length);};
	//! Set the end arrow length (in pixels)
	void SetEndArrowLength(double length)	{	m_EndArrow.m_dLength=__max(0,length);};
	//! Set the start arrow thick (in pixels)
	void SetStartArrowThick(double thick)	{	m_StartArrow.m_dThick=__max(0,thick);};
	//! Set the end arrow thick (in pixels)
	void SetEndArrowThick(double thick)		{	m_StartArrow.m_dThick=__max(0,thick);};
	//@}

	//! \name Data manipulation
	//@{
    //! returns $x(i)$
    double GetXi(UINT i) const { ASSERT(m_pX); ASSERT(i>=0 && i<m_pX->size()); return (*m_pX)[i];};
    //! returns $y(i)$
    double GetYi(UINT i) const { ASSERT(m_pY); ASSERT(i>=0 && i<m_pY->size()); return (*m_pY)[i];};

    //! returns the number of points
    size_t GetNPoints() { if(!m_pX || !m_pY) return 0; return __min(m_pX->size(), m_pY->size());};
    //! returns a pointer to \f$x\f$ array
	const CPGLDataPtr GetX()	const		{   return m_pX;};
    //! returns a pointer to \f$x\f$ array, const
	CPGLDataPtr GetX()					{   return m_pX;};
    //! returns a pointer to \f$y\f$ array
    const CPGLDataPtr GetY() const		{   return m_pY;};
    //! returns a pointer to \f$y\f$ array, const
    CPGLDataPtr GetY()					{   return m_pY;};

	//! return index to extremal points
	const CPGLRectU& GetLimitIndices() const	{	return m_rLimitIndices;};


	/*! Setting the data

	\param pX pointer to CPGLData
	\param pY pointer to CPGLData
	Sets pX and pY as the vector of data. 
	Previous data, if any, is deleted.
	*/
	virtual void SetDatas(CPGLDataPtr pX, CPGLDataPtr pY);
	/*! Setting data as vectors of double

	This is a helper function that uses the generic form of SetDatas and spares the user the creation of CPGLData objects.
	\param bMakeOwnCopy if true, a copy of the data is stored, otherwize only the reference is stored (default is true)
	*/
    virtual void SetDatas(const std::vector<double>& vx, const std::vector<double>& vy, bool bMakeCopy = true);
	/*! Setting data as vectors of double

	This is a helper function that uses the generic form of SetDatas and spares the user the creation of CPGLData objects.
	\param bMakeOwnCopy if true, a copy of the data is stored, otherwize only the reference is stored (default is true)
	*/
    virtual void SetDatas(const std::vector<float>& vx, const std::vector<float>& vy, bool bMakeCopy = true);
	/*! Setting data as vectors of double

	This is a helper function that uses the generic form of SetDatas and spares the user the creation of CPGLData objects.
	\param bMakeOwnCopy if true, a copy of the data is stored, otherwize only the reference is stored (default is true)
	*/
    virtual void SetDatas(const std::vector<int>& vx, const std::vector<int>& vy, bool bMakeCopy = true);
	/*! Setting data as vectors of double

	This is a helper function that uses the generic form of SetDatas and spares the user the creation of CPGLData objects.
	\param bMakeOwnCopy if true, a copy of the data is stored, otherwize only the reference is stored (default is true)
	*/
    virtual void SetDatas(const std::vector<BYTE>& vx, const std::vector<BYTE>& vy, bool bMakeCopy = true);
	
    virtual void CPGLLine2D::SetDatas(const std::vector<float>::iterator startX, 
                                      const std::vector<float>::iterator startY,
                                      size_t numberOfPoints);


    //! Delete current data
	void ClearData();
	//@}

	//! \name Serialization and debugging
	//@{
	//! Saving setttings to XML
	void SerializeXML(CPGLArchive& ar);
    //! Debuggin functions
    #ifdef _DEBUG
        virtual void Dump( CDumpContext& dc ) const;
        virtual void AssertValid() const;    // Override
    #endif
    //@}
protected:
	//! \name Virtual functions override
	//@{
	virtual void PlotArrowsGfx(gfxinterface::CGfxInterface& gfx);
	virtual void PlotLineStripGfx(gfxinterface::CGfxInterface& gfx);
	virtual void PlotPointStripGfx(gfxinterface::CGfxInterface& gfx);
	//@}

protected:
    /*! \name Attributes*/
    //@{
    //! array of $x(i)$
	CPGLDataPtr m_pX;
    //! array of $y(i)$
	CPGLDataPtr m_pY;
	//! Start Arrow
	SPGLArrow m_StartArrow;
	//! Start Arrow
	SPGLArrow m_EndArrow;
    //@}
private:
	CPGLRectU m_rLimitIndices;
};


PGL_DECLARE_SMARTPTR( CPGLLine2D );

/*! CPGLLine2DList

  A list of pointers to CPGLLine2D

\ingroup PGLLineGroup
*/
typedef std::list<CPGLLine2DPtr> CPGLLine2DList;

#endif // !defined(AFX_LINE2DGL_H__4DACBB78_9EFC_11D4_8A95_D4B14EEC3D7F__INCLUDED_)
